﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace comm
{
    public class TreeNodeCollection : IEnumerable<TreeNode>
    {
        public int Count { get { return _nodeList.Count; } }

        TreeNode _node = null;
        List<TreeNode> _nodeList = new List<TreeNode>();

        public TreeNodeCollection(TreeNode node)
        {
            _node = node;
        }

        public void AddRange(IEnumerable<TreeNode> collection)
        {
            foreach (var item in collection)
            {
                Add(item);
            }
        }
        public void Add(TreeNode item)
        {
            item.Parent = _node;
            _nodeList.Add(item);
        }
        public TreeNode this[int index]
        {
            get
            {
                return _nodeList[index];
            }
        }
        public void RemoveAt(int index)
        {
            _nodeList.RemoveAt(index);
        }
        public void Clear()
        {
            _nodeList.Clear();
        }

        public IEnumerator<TreeNode> GetEnumerator()
        {
            return _nodeList.GetEnumerator();
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }

    public class TreeNode
    {
        public static TreeNode Find(TreeNode node, string key)
        {
            if (node.Key == key)
            {
                return node;
            }
            TreeNode findnode = null;
            foreach (var item in node.Children)
            {
                var n2 = Find(item, key);
                if (n2 != null)
                {
                    findnode = n2;
                    break;
                }

            }
            return findnode;
        }
        public static List<TreeNode> Create(Dictionary<string, objst.ILinearTreeNode> nodeDic)
        {
            var rootList = new List<TreeNode>();
            foreach (var key in nodeDic.Keys)
            {
                var item = nodeDic[key];
                if (item.Parent == null || !nodeDic.ContainsKey(item.Parent))
                {
                    rootList.Add(new TreeNode(key, item.Name));
                }
            }
            foreach (var node in rootList)
            {
                FillChildren(node, nodeDic);
            }
            return rootList;
        }
        static void FillChildren(TreeNode node, Dictionary<string, objst.ILinearTreeNode> nodeDic)
        {
            foreach (var key in nodeDic.Keys)
            {
                var item = nodeDic[key];
                if (item.Parent != null && node.Key == item.Parent)
                {
                    var subNode = new TreeNode(key, item.Name, node);
                    FillChildren(subNode, nodeDic);
                    node.Children.Add(subNode);
                }
            }
        }

        public string Key { get; set; }
        public string Name { get; set; }
        public TreeNodeCollection Children { get; private set; }
        public TreeNode Parent { get; set; }

        public TreeNode(string key, string name, TreeNode parent = null)
        {
            Key = key;
            Name = name;
            Parent = parent;
            Children = new TreeNodeCollection(this);
        }

        public bool Remove(string key)
        {
            for (int i = 0, len = Children.Count; i < len; i++)
            {
                var item = Children[i];
                if (item.Key == key)
                {
                    Children.RemoveAt(i);
                    return true;
                }
            }
            return false;
        }
        public TreeNode Find(string key)
        {
            return Find(this, key);
        }
        public Dictionary<string, objst.LinearTreeNode> ToNodeDic(bool removeSelf = false)
        {
            var nodeDic = new Dictionary<string, objst.LinearTreeNode>();
            if (!removeSelf)
            {
                if (!nodeDic.ContainsKey(Key))
                {
                    nodeDic.Add(Key, new objst.LinearTreeNode
                    {
                        Name = Name,
                        Parent = Parent != null ? Parent.Key : ""
                    });
                }
            }

            foreach (var node in Children)
            {
                var dic = node.ToNodeDic();
                foreach (var key in dic.Keys)
                {
                    if (!nodeDic.ContainsKey(key))
                    {
                        nodeDic.Add(key, dic[key]);
                    }
                }
            }
            return nodeDic;
        }
    }
}
